﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Text;
using System.Windows.Forms;

namespace Ling.ZhControls
{
    /// <summary>
    /// Ling个性窗体。
    /// </summary>
    public class LingForm : Form
    {
        #region 初始化部份
        private Size NormalSize;
        private Point NormalLocation;

        public LingForm()
        {
            InitializeComponent();
        }

        /// <summary>
        /// 初始化窗体组件。
        /// </summary>
        private void InitializeComponent()
        {
            this.SuspendLayout();
            // 
            // LingForm
            // 
            NormalSize = this.Size;
            NormalLocation = this.Location;
            this.BackColor = Color.White;
            this.ClientSize = new System.Drawing.Size(292, 273);
            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
            this.Name = "LingForm";
            this.ResumeLayout(false);
            this.DoubleBuffered = true;

        }
        #endregion

        #region 扩展属性定义

        private Color _BorderColor = Color.FromArgb(50, 71, 102);

        /// <summary>
        /// 获取或设置窗体边框颜色
        /// </summary>
        [Browsable(true), Category("Appearance"), Description("获取或设置窗体边框的颜色")]
        public Color BorderColor
        {
            set { _BorderColor = value; this.Invalidate(); }
            get { return _BorderColor; }
        }

        private Color _BackColor2 = Color.FromArgb(207, 231, 255);

        /// <summary>
        /// 获取或设置窗体背景色2
        /// </summary>
        [Browsable(true), Category("Appearance"), Description("获取或设置窗体背景色2")]
        public Color BackColor2
        {
            set { _BackColor2 = value; }
            get { return _BackColor2; }
        }

        private int _Radius = 4;

        /// <summary>
        /// 获取或设置圆角承度
        /// </summary>
        [Browsable(true), Category("Appearance"), Description("获取或设置圆角承度")]
        public int Radius
        {
            get { return _Radius; }
            set { _Radius = value; this.Invalidate(); }
        }

        private int _TitleHeight = 25;

        /// <summary>
        /// 获取或设置窗体标题高度
        /// </summary>
        [Browsable(true), Category("Appearance"), Description("获取或设置窗体标题高度")]
        public int TitleHeight
        {
            set { _TitleHeight = value; if (_TitleHeight > 0) this.Invalidate(); }
            get { return _TitleHeight; }
        }

        private Color _TitleBackColor1 = Color.FromArgb(244, 250, 255);

        /// <summary>
        /// 获取或设置起始标题背景色。
        /// </summary>
        [Browsable(true), Category("Appearance"), Description("获取或设置起始标题背景色。")]
        public Color TitleBackColor1
        {
            set { _TitleBackColor1 = value; }
            get { return _TitleBackColor1; }
        }

        private Color _TitleBackColor2 = Color.FromArgb(207, 231, 255);

        /// <summary>
        /// 获取或设置结束标题背景色。
        /// </summary>
        [Browsable(true), Category("Appearance"), Description("获取或设置结束标题背景色。")]
        public Color TitleBackColor2
        {
            set { _TitleBackColor2 = value; }
            get { return _TitleBackColor2; }
        }

        private Color _TitleBottomLine = Color.FromArgb(136, 167, 198);

        /// <summary>
        /// 获取或设置标题栏底部分隔线颜色。
        /// </summary>
        [Browsable(true), Category("Appearance"), Description("获取或设置标题栏底部分隔线颜色。")]
        public Color TitleBottomLine
        {
            set { _TitleBottomLine = value; }
            get { return _TitleBottomLine; }
        }

        private Color _TextColor = Color.FromArgb(48, 100, 165);

        /// <summary>
        /// 获取或设置标题文本颜色。
        /// </summary>
        [Browsable(true), Category("Appearance"), Description("获取或设置标题文本颜色。")]
        public Color TextColor
        {
            set { _TextColor = value; }
            get { return _TextColor; }
        }

        [Browsable(false), Category("Appearance")]
        public new FormBorderStyle FormBorderStyle
        {
            set { base.FormBorderStyle = value; }
            get { return base.FormBorderStyle; }
        }

        private FormWindowState _WindowState = FormWindowState.Normal;

        /// <summary>
        /// 获取或设置窗口状态。
        /// </summary>
        [Browsable(true), Category("Layout"), Description("获取或设置窗口状态。")]
        public new FormWindowState WindowState
        {
            set
            {
                _WindowState = value;
                switch (_WindowState)
                { 
                    case FormWindowState.Maximized :
                        int _W = Screen.PrimaryScreen.WorkingArea.Width;
                        int _H = Screen.PrimaryScreen.WorkingArea.Height;
                        this.Location = new Point(0, 0);
                        this.Size = new Size(_W, _H);
                        break;
                    case FormWindowState.Minimized :
                        base.WindowState = FormWindowState.Minimized;
                        break;
                    case FormWindowState.Normal :
                        base.WindowState = FormWindowState.Normal;
                        this.Size = NormalSize;
                        this.Location = NormalLocation;
                        break;
                }
            }
            get { return _WindowState; }
        }

        /// <summary>
        /// 是否允许调整窗口大小。
        /// </summary>
        [Browsable(true), Description("是否允许调整窗口大小。")]
        private bool _AllowResize = true;

        public bool AllowResize
        {
            set { _AllowResize = value; }
            get { return _AllowResize; }
        }

        #endregion

        #region 窗体绘制部份

        /// <summary>
        /// 创建圆角矩形路径。
        /// </summary>
        /// <param name="rect"></param>
        /// <param name="cornerRadius"></param>
        /// <returns></returns>
        internal static GraphicsPath CreateRoundedRectanglePath(Rectangle rect, int cornerRadius)
        {
            GraphicsPath roundedRect = new GraphicsPath();
            roundedRect.AddArc(rect.X, rect.Y, cornerRadius * 2, cornerRadius * 2, 180, 90);
            roundedRect.AddLine(rect.X + cornerRadius, rect.Y, rect.Right - cornerRadius * 2, rect.Y);
            roundedRect.AddArc(rect.X + rect.Width - cornerRadius * 2, rect.Y, cornerRadius * 2, cornerRadius * 2, 270, 90);
            roundedRect.AddLine(rect.Right, rect.Y + cornerRadius * 2, rect.Right, rect.Y + rect.Height - cornerRadius * 2);
            roundedRect.AddArc(rect.X + rect.Width - cornerRadius * 2, rect.Y + rect.Height - cornerRadius * 2, cornerRadius * 2, cornerRadius * 2, 0, 90);
            roundedRect.AddLine(rect.Right - cornerRadius * 2, rect.Bottom, rect.X + cornerRadius * 2, rect.Bottom);
            roundedRect.AddArc(rect.X, rect.Bottom - cornerRadius * 2, cornerRadius * 2, cornerRadius * 2, 90, 90);
            roundedRect.AddLine(rect.X, rect.Bottom - cornerRadius * 2, rect.X, rect.Y + cornerRadius * 2);
            roundedRect.CloseFigure();
            return roundedRect;
        }

        /// <summary>
        /// 绘制边框。
        /// </summary>
        /// <param name="g"></param>
        protected void DrawBorder(Graphics g)
        {
            try
            {
                Rectangle Rect = new Rectangle(0, 0, this.Width, this.Height);
                if (Rect.Width < 1 || Rect.Height < 1) return;
                GraphicsPath borderPath = CreateRoundedRectanglePath(Rect, Radius);
                this.Region = new Region(borderPath);
                g.DrawPath(new Pen(BorderColor), CreateRoundedRectanglePath(new Rectangle(0, 0, this.Width - 1, this.Height - 1), Radius));
            }
            catch 
            {
                this.Width++;
                this.Height++;
                DrawBorder(g);
            }
        }

        /// <summary>
        /// 绘制标题栏
        /// </summary>
        /// <param name="g"></param>
        protected void DrawTitle(Graphics g)
        {
            if (TitleHeight < 1) return;
            Rectangle tRect = new Rectangle(1, 1, this.Width - 2, TitleHeight - 1);
            if (tRect.Width < 1 || tRect.Height < 1) return;
            GraphicsPath titlePath = new GraphicsPath();
            titlePath.AddArc(tRect.X, tRect.Y, Radius * 2, Radius * 2, 180, 90);
            titlePath.AddLine(tRect.X + Radius, tRect.Y, tRect.Right - Radius * 2, tRect.Y);
            titlePath.AddArc(tRect.X + tRect.Width - Radius * 2, tRect.Y, Radius * 2, Radius * 2, 270, 90);
            titlePath.AddLine(tRect.Right, tRect.Y + Radius * 2, tRect.Right, tRect.Y + tRect.Height - Radius * 2);
            titlePath.AddLine(tRect.X + tRect.Width, tRect.Y + tRect.Height, tRect.X, tRect.Y + tRect.Height);
            titlePath.AddLine(tRect.X, tRect.Y + tRect.Height, tRect.X, tRect.Y + Radius);
            LinearGradientBrush lgb = new LinearGradientBrush(tRect, TitleBackColor1, TitleBackColor2, LinearGradientMode.Vertical);
            g.FillPath(lgb, titlePath);
            GraphicsPath bottomLine = new GraphicsPath();
            bottomLine.AddLine(tRect.X + 1, tRect.Y + TitleHeight, tRect.Right - 1, tRect.Y + TitleHeight);
            g.DrawPath(new Pen(TitleBottomLine), bottomLine);
            Font TxtFont = new Font(this.Font.Name, this.Font.Size, FontStyle.Bold);
            g.DrawString(this.Text, TxtFont, new SolidBrush(TextColor), 25, (TitleHeight - TxtFont.Size) / 2);
        }

        /// <summary>
        /// 绘制工作区域背景
        /// </summary>
        /// <param name="g"></param>
        protected void DrawBackGround(Graphics g)
        {
            Rectangle bckRect = new Rectangle(1, TitleHeight + 1, this.Width - 3, this.Height - 3 - TitleHeight);
            GraphicsPath bp = CreateRoundedRectanglePath(bckRect, Radius);
            if (bckRect.Width < 1 || bckRect.Height < 1) return;
            LinearGradientBrush lgb = new LinearGradientBrush(bckRect, BackColor, BackColor2, LinearGradientMode.Vertical);
            Blend ble = new Blend();
            ble.Positions = new float[] { 0f, .3f, 1.0f };
            ble.Factors = new float[] { 0f, .3f, 1.0f };
            lgb.Blend = ble;
            //g.FillRectangle(lgb, bckRect);
            g.FillPath(lgb, bp);
        }

        /// <summary>
        /// 绘制窗口图标。
        /// </summary>
        /// <param name="g"></param>
        private void DrawIcon(Graphics g)
        {
            if (this.Icon == null) return;
            g.DrawIcon(this.Icon, new Rectangle(6, (int)((TitleHeight - 16) / 2), 16, 16));
        }

        //protected override void OnPaintBackground(PaintEventArgs e)
        //{
        //    base.OnPaintBackground(e);
        //    Graphics g = e.Graphics;
        //    g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
        //    g.DrawImage(_cache, new Point(0, 0));
        //}

        Bitmap _cache =null;


        private void ReDrawCache() 
        {
            _cache = null;
            _cache = new Bitmap(this.Width, this.Height);
            Graphics g = Graphics.FromImage(_cache);
            
            DrawBorder(g);
            DrawTitle(g);
            DrawBackGround(g);
            DrawIcon(g);
        }

        protected override void OnLoad(EventArgs e)
        {
            
            base.OnLoad(e);
            ReDrawCache();
        }
        /// <summary>
        ///// 截获系统消息以进行窗体绘制。
        ///// </summary>
        ///// <param name="m"></param>
        //protected override void WndProc(ref Message m)
        //{
        //    base.WndProc(ref m);

        //    IntPtr hDC = WinAPI.GetWindowDC(m.HWnd);
        //    if (hDC.ToInt32() == 0) return;
        //    switch (m.Msg)
        //    {
                    
        //        case 0xf:
        //        case 0x133:
                    
        //            //Graphics g = Graphics.FromHdc(hDC);
        //            //g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
        //            //g.DrawImage(_cache, new Point(0, 0));
        //            //Graphics g = Graphics.FromImage(_cache);
                    
        //            //DrawBorder(g);
        //            //DrawTitle(g);
        //            //DrawBackGround(g);
        //            //DrawIcon(g);
        //            break;
        //    }
        //}

        protected override void OnPaint(PaintEventArgs e)
        {
            Graphics g = e.Graphics;
            g.Clear(Color.White);
            g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
            g.DrawImage(_cache, new Point(0, 0));
            base.OnPaint(e);
        }

        protected override void OnTextChanged(EventArgs e)
        {
            base.OnTextChanged(e);
        }

        #endregion

        #region 移动或大小调整

        /// <summary>
        /// 表示调整方向的枚举。
        /// </summary>
        private enum ResizeFlg
        { 
            LeftT  = 0x01,
            Left   = 0x02,
            Top    = 0x03,
            RightT = 0x04,
            Right  = 0x05,
            RightB = 0x06,
            Bottom = 0x07,
            LeftB  = 0x08,
            None = 0x09
        }

        private bool _MouseDown = false; //标识是否按下鼠标左键
        private int _MouseX, _MouseY, _MsizeX, _MsizeY;  //记录上次的鼠标位置。
        private bool _Resizeing = false, _Movieing = false; // 是否处于大小调整状态。
        private ResizeFlg ResizeFlag = ResizeFlg.None;  // 调整模式。

        /// <summary>
        /// 按指定的模式对窗口进行大小调整。
        /// </summary>
        /// <param name="flg">调整方向。</param>
        /// <param name="ResizeX">X轴调整值。</param>
        /// <param name="ResizeY">Y轴调整值。</param>
        private void ResizeForm(ResizeFlg flg, int MouseX, int MouseY)
        {
            switch (flg)
            { 
                case ResizeFlg.Bottom :
                    this.Height += MouseY - _MsizeY;
                    break;
                case ResizeFlg.Left :
                    this.Left += MouseX - _MsizeX;
                    this.Width += _MsizeX - MouseX;
                    break;
                case ResizeFlg.LeftB :
                    this.Left += MouseX - _MsizeX;
                    this.Width += _MsizeX - MouseX;
                    this.Height += MouseY - _MsizeY;
                    break;
                case ResizeFlg.LeftT :
                    this.Left += MouseX - _MsizeX;
                    this.Top += MouseY - _MsizeY;
                    this.Width += _MsizeX - MouseX;
                    this.Height += _MsizeY - MouseY;
                    break;
                case ResizeFlg.Right :
                    this.Width += MouseX - _MsizeX;
                    break;
                case ResizeFlg.RightB :
                    this.Width += MouseX - _MsizeX;
                    this.Height += MouseY - _MsizeY;
                    break;
                case ResizeFlg.RightT :
                    this.Top += MouseY - _MsizeY;
                    this.Width += MouseX - _MsizeX;
                    this.Height += MouseY - _MsizeY;
                    break;
                case ResizeFlg.Top :
                    if (this.Top > 0)
                        this.Top += MouseY - _MsizeY;
                    else
                        this.Top = 0;
                    this.Height += _MsizeY - MouseY;
                    break;
            }
            _MsizeX = MouseX;
            _MsizeY = MouseY;
            
        }

        protected override void OnMouseDoubleClick(MouseEventArgs e)
        {
            base.OnMouseDoubleClick(e);
            if (!AllowResize) 
            {
                return;
            }
            if (e.X > 0 && e.Y < TitleHeight)
            {
                switch (WindowState)
                { 
                    case FormWindowState.Maximized :
                        WindowState = FormWindowState.Normal;
                        break;
                    case FormWindowState.Normal :
                        WindowState = FormWindowState.Maximized;
                        break;
                }
            }
        }

        /// <summary>
        /// 调整大小后需要重绘窗口。
        /// </summary>
        /// <param name="e"></param>
        protected override void OnResize(EventArgs e)
        {
            base.OnResize(e);
            if (WindowState == FormWindowState.Normal)
                NormalSize = this.Size;
            ReDrawCache();
            this.Refresh();
            //this.Invalidate(new Rectangle(this.Top,this.Width,this.Width,this.Height));
            
        }

        protected override void OnMove(EventArgs e)
        {
            base.OnMove(e);
            if (WindowState == FormWindowState.Normal)
                NormalLocation = this.Location;
        }

        /// <summary>
        /// 鼠标按下时标识其已按下，并记录鼠标的当前座标以备后面的移动之用。
        /// </summary>
        /// <param name="e"></param>
        protected override void OnMouseDown(MouseEventArgs e)
        {
            base.OnMouseDown(e);

            if (e.Button == MouseButtons.Left)
            {
                _MouseDown = true;
                _MouseX = e.X;
                _MouseY = e.Y;
                _MsizeX = e.X;
                _MsizeY = e.Y;
            }
        }

        /// <summary>
        /// 鼠标弹起时标识其未按下，并清掉记录的座标。
        /// </summary>
        /// <param name="e"></param>
        protected override void OnMouseUp(MouseEventArgs e)
        {
            base.OnMouseUp(e);

            _MouseDown = false;
            _MouseX = 0;
            _MouseY = 0;
            _MsizeX = 0;
            _MsizeY = 0;
            _Movieing = false;
            _Resizeing = false;
            ResizeFlag = ResizeFlg.None;
            this.Cursor = Cursors.Default;
        }

        /// <summary>
        /// 当鼠标移动时，此处要调整大小，实现8个点的调节控制。
        /// </summary>
        /// <param name="e"></param>
        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);

            // 窗口移动部份。
            if (_MouseDown && this.WindowState != FormWindowState.Maximized && !_Resizeing)
            {
                int _X = e.X - _MouseX;
                int _Y = e.Y - _MouseY;
                if (!_Movieing)
                {
                    if (e.X > 0 && e.Y < TitleHeight)
                    {   //仅能在标题部份移动窗口。
                        _Movieing = true;
                        this.Cursor = Cursors.Hand;
                        this.Location = new Point(this.Left + _X, this.Top + _Y);
                    }
                }
                else
                {
                    this.Cursor = Cursors.Default;
                    this.Location = new Point(this.Left + _X, this.Top + _Y);
                }
            }

            if (AllowResize)
            {
                 // 窗口大小调整判断
                if (!_Resizeing && !_Movieing)
                {
                    const int offset = 3;
                    if (e.X < offset && e.Y > offset && e.Y < (this.Height - offset))  // 向左调整。
                    {
                        ResizeFlag = ResizeFlg.Left;
                        this.Cursor = Cursors.SizeWE;
                        _Resizeing = true;
                    }
                    else if (e.X < Radius && e.Y < Radius) // 向左上或左下调整。
                    {
                        ResizeFlag = ResizeFlg.LeftT;
                        this.Cursor = Cursors.SizeNWSE;
                        _Resizeing = true;
                    }
                    else if (e.X > offset && e.X < (this.Width - offset) && e.Y < offset) // 向上调整。
                    {
                        ResizeFlag = ResizeFlg.Top;
                        this.Cursor = Cursors.SizeNS;
                        _Resizeing = true;
                    }
                    else if (e.X > (this.Width - Radius) && e.Y < Radius) // 向右上或右下调整。
                    {
                        ResizeFlag = ResizeFlg.RightT;
                        this.Cursor = Cursors.SizeNESW;
                        _Resizeing = true;
                    }
                    else if (e.X > (this.Width - offset) && e.Y > offset && e.Y < (this.Height - offset)) // 向右调整。
                    {
                        ResizeFlag = ResizeFlg.Right;
                        this.Cursor = Cursors.SizeWE;
                        _Resizeing = true;
                    }
                    else if (e.X > (this.Width - Radius) && e.Y > (this.Height - Radius)) // 向右下或右上调整。
                    {
                        ResizeFlag = ResizeFlg.RightB;
                        this.Cursor = Cursors.SizeNWSE;
                        _Resizeing = true;
                    }
                    else if (e.X > offset && e.X < (this.Width - offset) && e.Y > (this.Height - offset)) // 向下调整。
                    {
                        ResizeFlag = ResizeFlg.Bottom;
                        this.Cursor = Cursors.SizeNS;
                        _Resizeing = true;
                    }
                    else if (e.X < Radius && e.Y > (this.Height - Radius)) // 向左下或左上调整。
                    {
                        ResizeFlag = ResizeFlg.LeftB;
                        this.Cursor = Cursors.SizeNESW;
                        _Resizeing = true;
                    }
                    else
                    {
                        _Resizeing = false;
                        this.Cursor = Cursors.Default;
                    }

                    if (_MouseDown) ResizeForm(ResizeFlag, e.X, e.Y);
                }
                else
                {
                    if (_MouseDown && !_Movieing)
                    {
                        ResizeForm(ResizeFlag, e.X, e.Y);
                    }
                    else
                    {
                        _Resizeing = false;
                        this.Cursor = Cursors.Default;
                    }
                }
            }
        }

        #endregion
    }
}
